﻿//-----------------------------------------------------------------------
// <copyright file="UnhandledExceptionUnitTest.cs" company="CodePlex">
//     Copyright (c) Doug Holland, CodePlex. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace CodePlex.Diagnostics.Contracts
{
    using System;

    using System.IO;

    using System.Runtime.Serialization;
    using System.Runtime.Serialization.Formatters.Binary;

    using Microsoft.VisualStudio.TestTools.UnitTesting;

    /// <summary>
    /// Provides unit tests for the <see cref="T:CodePlex.Diagnostics.UnhandledException"/> class.
    /// </summary>
    [TestClass]
    public sealed class UnhandledExceptionUnitTest
    {
        #region public UnhandledExceptionUnitTest()

        /// <summary>
        /// Initializes a new instance of the <see cref="T:UnhandledExceptionUnitTest"/> class.
        /// </summary>
        public UnhandledExceptionUnitTest()
        {
        }

        #endregion

        #region public TestContext TestContext

        /// <summary>
        /// Gets or sets the test context which provides information about and functionality for the current test run.
        /// </summary>
        public TestContext TestContext
        {
            get;
            set;
        }

        #endregion

        #region public void UnhandledExceptionConstructorUnitTest()

        /// <summary>
        /// Ensures that the constructor of the <see cref="T:CodePlex.Diagnostics.UnhandledException"/> class.
        /// </summary>
        [TestMethod]
        public void UnhandledExceptionConstructorUnitTest()
        {
            // disable warning for the use of obsolete code.
            #pragma warning disable 618

            // establish an instance of the UnhandledException class using the default constructor.
            UnhandledException unhandledException = new UnhandledException();

            // ensure the exception is not null.
            Assert.IsNotNull(unhandledException);

            // ensure the inner exception is null.
            Assert.IsNull(unhandledException.InnerException);

            // establish an instance of the UnhandledException class using the constructor that accepts a single argument of type string.
            unhandledException = new UnhandledException("exception message");

            // ensure the exception is not null.
            Assert.IsNotNull(unhandledException);

            // ensure the inner exception is null.
            Assert.IsNull(unhandledException.InnerException);

            // ensure the message is correctly set for the exception.
            Assert.AreEqual<string>("exception message", unhandledException.Message);

            // establish an instance of the UnhandledException class using the constructor that accepts two arguments, one of type string and the other an inner-exception.
            unhandledException = new UnhandledException("exception message", new InvalidOperationException());

            // ensure the exception is not null.
            Assert.IsNotNull(unhandledException);

            // ensure the message is correctly set for the exception.
            Assert.AreEqual<string>("exception message", unhandledException.Message);

            // restore warning for the use of obsolete code.
            #pragma warning restore 618
            
            try
            {
                for (int index = 0; index < 10; index++)
                {
                    index /= index;
                }
            }
            catch (DivideByZeroException ex)
            {
                // disable warning for the use of obsolete code.
                #pragma warning disable 618
                
                // establish an instance of the UnhandledException class based upon the DivideByZeroException encountered above.
                unhandledException = new UnhandledException(ex);

                // restore warning for the use of obsolete code.
                #pragma warning restore 618

                // ensure the exception is not null.
                Assert.IsNotNull(unhandledException);

                // ensure the inner exception is not null.
                Assert.IsNotNull(unhandledException.InnerException);
            }

            try
            {
                // establish an instance of the BinaryFormatter to use for testing the serialization and deserialization of the UnhandledException class.
                IFormatter formatter = new BinaryFormatter() as IFormatter;

                using (MemoryStream stream = new MemoryStream())
                {
                    // serialize the UnhandledException into a memory stream.
                    formatter.Serialize(stream, unhandledException);

                    // reset the stream position to the beginning of the stream.
                    stream.Seek(0, SeekOrigin.Begin);

                    // read the stream into a byte array.
                    byte[] buffer = new byte[stream.Length];
                    stream.Read(buffer, 0, buffer.Length);

                    // seek to the beginning of the stream.
                    stream.Seek(0, SeekOrigin.Begin);

                    // disable warning for the use of obsolete code.
                    #pragma warning disable 618

                    // deserialize the UnhandledException from the memory stream.
                    UnhandledException deserializedException = formatter.Deserialize(stream) as UnhandledException;

                    // restore warning for the use of obsolete code.
                    #pragma warning restore 618

                    // ensure the deserialized exception is not null.
                    Assert.IsNotNull(deserializedException);

                    // ensure the inner exception is not null.
                    Assert.IsNotNull(deserializedException.InnerException);
                }
            }
            catch (SerializationException ex)
            {
                // exception occurred during either serialization or deserialization, unit test fails...
                Assert.Fail(ex.Message);
            }
        }

        #endregion
    }
}